/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Sylvain Sicard - initial API and implementation
 ******************************************************************************/
/**
 * Feb 21, 2008
 * ssicard
 */
package fr.jade.fraclite.orb;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import org.objectweb.fractal.api.Interface;

import fr.jade.fraclite.orb.api.Binder;
import fr.jade.fraclite.orb.api.Name;
import fr.jade.fraclite.orb.api.NamingException;
import fr.jade.fraclite.orb.names.JGroupsName;
import fr.jade.fraclite.orb.names.TcpIpName;

/**
 * @author Sylvain Sicard
 *
 */
public class BasicBinder implements Binder {

  ClassLoader cl = null;
  
  Map<Long, Skeleton> unicastExportedInterfaces;
  Map<Long, Skeleton> multicastExportedInterfaces;
  Map<Name, Object>   localInterfaces;
  Map<Name, Object>   bindedInterfaces;
  StubFactory unicastStubfactory = null;
  StubFactory multicastStubfactory = null;
  
  public BasicBinder() throws NamingException{
    cl = getClass().getClassLoader();
    unicastStubfactory = new UnicastStubFactory(cl);
    multicastStubfactory = new MulticastStubFactory(cl);
    unicastExportedInterfaces = new TreeMap<Long, Skeleton>();
    multicastExportedInterfaces = new TreeMap<Long, Skeleton>();
    localInterfaces = new HashMap<Name, Object>();
    bindedInterfaces = new HashMap<Name, Object>();
  }
  
  public synchronized Object bind(Name n, Object hints) throws NamingException {
    Object stub = null;
    if(localInterfaces.containsKey(n)){
      System.out.println("[Binder] optimize local reference");
      stub = localInterfaces.get(n);
    }else if(bindedInterfaces.containsKey(n)){
      stub = bindedInterfaces.get(n);
    }else{
      if (n instanceof TcpIpName){
        stub = unicastStubfactory.newStub(this, n);
      }else if (n instanceof JGroupsName){
        stub = multicastStubfactory.newStub(this, n);
        //System.out.println("stub is "+ stub);
      }else{
        throw new NamingException("Name unknown");
      }
      //bindedInterfaces.put(n, stub);
    }
    return stub;
  }

  @SuppressWarnings("unchecked")
  @Override
  public synchronized Name export(Object o, Object hints) throws NamingException {
    assert hints == null || hints instanceof Map : "hints must be instance of Map";
    assert o instanceof Interface : "Cannot export an object which is not instance of Interface";
    Interface itf = (Interface)o;
    Skeleton skel = null;
    
    // TODO determine if we have to export itf with unicast or multicast
    if(multicastExportedInterfaces.containsKey(itf.getFcItfGUId())){
      skel = multicastExportedInterfaces.get(itf.getFcItfGUId());
    }else{
      skel = (Skeleton)multicastStubfactory.newSkeleton((Map)hints, o, this);
      multicastExportedInterfaces.put(itf.getFcItfGUId(), skel);
    }
    
//    if(unicastExportedInterfaces.containsKey(itf.getFcItfGUId())){
//      skel = unicastExportedInterfaces.get(itf.getFcItfGUId());
//    }else{
//      skel = (Skeleton)rmiStubfactory.newSkeleton((Map)hints, itf, this);
//      unicastExportedInterfaces.put(itf.getFcItfGUId(), skel);
//    }
    
    Name n = skel.getName(o);
    //localInterfaces.put(n, o);
    return n;
  }

}
